using System;

namespace GURUCORE.Framework.DataAccess.ORMapping.CriteriaMapping
{
    [System.Diagnostics.DebuggerStepThrough]
	public class Expression : IOperand, IExpression
	{
        private IOperand m_oFirstOperand;
        public IOperand FirstOperand
        {
          get { return m_oFirstOperand; }
          set { m_oFirstOperand = value; }
        }

        private IOperand  m_oSecondOperand;
        public IOperand SecondOperand
        {
            get { return m_oSecondOperand; }
            set { m_oSecondOperand = value; }
        }
		
        private Operator m_oOperator;
        public Operator Operator
        {
            get { return m_oOperator; }
            set { m_oOperator = value; }
        }



        public Expression()
        { }

        public Expression(string p_sFieldOperand) : this(Operator.Value, new FieldOperand(p_sFieldOperand))
        {}

		public Expression(IOperand p_oFirstOperand, Operator p_oOperator, IOperand p_oSecondOperand)
		{
			if (p_oOperator.IsUnary())
			{
				throw new ExpressionException();
			}
			m_oFirstOperand = p_oFirstOperand;
			m_oOperator = p_oOperator;
			m_oSecondOperand = p_oSecondOperand;
		}

        public Expression(IOperand p_oFirstOperand, Operator p_oOperator, object p_oConstantOperand)
            : this(p_oFirstOperand, p_oOperator, new ConstantOperand(p_oConstantOperand))
        {            
        }

        public Expression(string p_sFirstFieldOperand, Operator p_oOperator, object p_oConstantOperand)
            : this(new FieldOperand(p_sFirstFieldOperand), p_oOperator, new ConstantOperand(p_oConstantOperand))
        { }

		public Expression(Operator p_oOperator, IOperand p_oSecondOperand)
		{
			if (!p_oOperator.IsUnary())
			{
				throw new ExpressionException();
			}
			m_oOperator = p_oOperator;
			m_oSecondOperand = p_oSecondOperand;
		}

		public Expression(IOperand p_oFirstOperand, Operator p_oOperator)
		{
			if (p_oOperator.IsUnary())
			{
				throw new ExpressionException();
			}
			m_oFirstOperand = p_oFirstOperand;
			m_oOperator = p_oOperator;
			m_oSecondOperand = new EmptyOperand();
		}



		public Expression And(Expression p_expSecond)
		{
			return new Expression(this, Operator.And, p_expSecond);
		}

       


		public Expression Or(Expression p_expSecond)
		{
			return new Expression(this, Operator.Or, p_expSecond);
		}

		public Expression XOr(Expression p_expSecond)
		{
			return new Expression(this, Operator.Xor, p_expSecond);
		}

		public Expression Not()
		{
			return new Expression(Operator.Not, this);
		}

		#region IOperand Members

		public virtual string ToExpressionString(IExpressionMaker p_oExpressionMaker)
		{            
			if (m_oOperator.IsUnary())
			{
				return "(" + m_oOperator.ToString() + " " + m_oSecondOperand.ToExpressionString(p_oExpressionMaker) + ")";
			}
			else
			{
				return "(" + m_oFirstOperand.ToExpressionString(p_oExpressionMaker) + " " + m_oOperator.ToString() + " " + m_oSecondOperand.ToExpressionString(p_oExpressionMaker) + ")";
			}
		}

		public override string ToString()
		{
			return ToExpressionString(new DefaultExpressionMaker());
		}

		#endregion


        
        public static Expression operator *(Expression p_expA, Expression p_expB)
        {
            return new Expression(p_expA, Operator.And, p_expB);
        }
        public static Expression operator +(Expression p_expA, Expression p_expB)
        {
            return new Expression(p_expA, Operator.Or, p_expB);
        }

        public static Expression TRUE
        {
            get
            {
                return new Expression("1", Operator.Eq, 1);
            }
        }

        public static Expression FALSE
        {
            get
            {
                return new Expression("1", Operator.Eq, -1);
            }
        }

	}
}
